package com.arsl.server;

import java.sql.Date;
import java.util.HashMap;
import java.util.UUID;

import org.apache.ibatis.session.SqlSession;

import com.arsl.client.PaperaziService;
import com.arsl.client.data.ARPage;
import com.arsl.client.data.Content;
import com.arsl.client.data.Edition;
import com.arsl.client.data.PageView;
import com.arsl.client.data.Paper;
import com.arsl.client.data.Publication;
import com.arsl.client.data.Publisher;
import com.arsl.client.data.Section;
import com.arsl.client.data.SectionStats;
import com.arsl.client.data.Tag;
import com.arsl.client.data.TagView;
import com.arsl.client.data.User;
import com.arsl.client.util.Constants.ContentStatus;
import com.arsl.client.util.Utils;
import com.arsl.server.db.DBHandler;
import com.arsl.server.db.DBMapper;
import com.google.gson.Gson;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class PaperaziServiceImpl extends RemoteServiceServlet implements
		PaperaziService {

	private static final String HOST_PREFIX = "http://localhost:8080/arsl";
	private static final String DOWNLOAD_PAGES_FOLDER = "/dw_pages";
	private static final String QR_CODES_FOLDER = "/qr_codes";

	public PageView viewPage(int arPageId, String auth) {
		PageView view = new PageView();
		view.setPageImageUrl(getPageImageUrl(arPageId));
		Paper paper = getPaperForArPage(arPageId);
		view.setPaper(paper);
		Tag[] tags = getTags(arPageId);
		TagView[] tagViews = new TagView[tags.length];
		TagView tagView;
		Content[] contents;
		for (int i = 0; i < tags.length; i++) {
			tagView = new TagView();
			tagView.setTag(tags[i]);
			contents = getContent(tags[i].id);
			tagView.setContent(contents);
			tagViews[i] = tagView;
		}
		view.setTagViews(tagViews);
		return view;
	}

	private Paper getPaperForArPage(int arPageId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Paper paper = new Paper();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			paper = mapper.getPaperForArPage(arPageId);
		} finally {
			session.close();
		}
		return paper;
	}

	public Integer[] signIn(String email, String password) {

		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		User user;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			user = mapper.getUser(email, password);
		} finally {
			session.close();
		}
		if (user == null) {
			return new Integer[] { 0, 0, 0 };
		}
		return new Integer[] { 1, user.getId(), user.getPublisherId() };
	}

	public String getPageImageUrl(int arPageId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		String url;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			url = mapper.getPageImageUrl(arPageId);
		} finally {
			session.close();
		}
		return url;
	}

	public Content[] getContent(int tagId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Content[] contents;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			contents = mapper.getContent(tagId);
		} finally {
			session.close();
		}
		return contents;
	}

	public Tag[] getTags(int arPageId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Tag[] tags;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			tags = mapper.getTags(arPageId);
		} finally {
			session.close();
		}
		return tags;
	}

	public int addPublisher(String name) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Publisher publisher = new Publisher();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			publisher.setName(name);
			id = mapper.addPublisher(publisher);
		} finally {
			session.close();
		}
		return id;
	}

	public int addUser(String email, String password, int publisherId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		int id = 0;
		User user = new User();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			user.setEmail(email);
			user.setPassword(password);
			user.setPublisherId(publisherId);
			id = mapper.addUser(user);
		} finally {
			session.close();
		}
		return id;
	}

	public boolean editPassword(String email, String newPassword) {
		return true;
	}

	public int addPaper(int publisherId, String name, String frequency,
			float height, float width) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		int id = 0;
		Paper paper = new Paper();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			paper.setFrequency(frequency);
			paper.setHeight(height);
			paper.setWidth(width);
			paper.setName(name);
			paper.setPublisherId(publisherId);
			id = mapper.addPaper(paper);
		} finally {
			session.close();
		}
		return id;

	}

	/**
	 * Adds a publication to this date and edition if not exists. if exists,
	 * simply return the id of that publication
	 * 
	 * @param paperId
	 * @param publishedDate
	 * @param editionId
	 * @return
	 */
	public int addPublication(int paperId, Date publishedDate, int editionId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Publication publication = new Publication();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			publication.setPaperId(paperId);
			publication.setEditionId(editionId);
			publication.setPublishDate(publishedDate);
			id = mapper.addPublication(publication);
		} finally {
			session.close();
		}
		return id;
	}

	/**
	 * 
	 * @param publicationId
	 * @param pageNumber
	 * @param httpSession
	 * @return the UUID embedded in the QR code of the AR Page
	 */
	public int addARPage(int publicationId, int sectionId, int pageNumber) {

		String uStr = publicationId + "&" + sectionId + "&" + pageNumber;
		String uuid = UUID.nameUUIDFromBytes(uStr.getBytes()).toString();

		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		ARPage arPage = new ARPage();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			arPage.setPublicationId(publicationId);
			arPage.setSectionId(sectionId);
			arPage.setPageNumber(pageNumber);
			arPage.setUUID(uuid);
			arPage.setImageUrl("");
			id = mapper.addArPage(arPage);
		} finally {
			session.close();
		}
		return id;
	}

	public boolean setARPageImage(int arpageId, String imageUrl) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		ARPage arPage = new ARPage();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			arPage.setId(arpageId);
			arPage.setImageUrl(imageUrl);
			mapper.setArPageImageUrl(arPage);
		} finally {
			session.close();
		}
		return true;
	}

	public boolean removeARPage(int ARPageId) {
		return true;
	}

	public int addTag(int arPageId, float startx, float starty, float height,
			float width) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Tag tag = new Tag();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			tag.setArPageId(arPageId);
			tag.setStartx(startx);
			tag.setStarty(starty);
			tag.setHeight(height);
			tag.setWidth(width);
			id = mapper.addTag(tag);
		} finally {
			session.close();
		}
		return id;
	}

	public boolean removeTag(int tagId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Content content = new Content();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			mapper.removeTag(tagId);
		} finally {
			session.close();
		}
		return true;
	}

	public boolean editTag(String tagId, float nstartx, float nstarty,
			float nheight, float nwidth) {
		return true;
	}

	/**
	 * Convenience function to add a content to a tag
	 */
	public int addContent(int tagId, int publisherId, String contentType,
			String title, String description, String url) {
		int contentId = createContent(publisherId, contentType, title,
				description, url);

		addContentToTag(tagId, contentId);

		return contentId;

	}

	public int updateTagContent(int tagId, Content[] contents) {
		for (Content content : contents) {
			if (content.getStatus().equals(ContentStatus.New)) {
				if (Utils.isValidContent(content)) {
					addContent(tagId, content.getPublisherId(),
							content.getType(), content.getTitle(),
							content.getDescription(), content.getUrl());
				}
			} else if (content.getStatus().equals(ContentStatus.Update)) {
				updateContent(content);
			} else if (content.getStatus().equals(ContentStatus.Delete)) {
				removeContentFromTag(tagId, content.getId());
			}
		}

		return tagId;
	}

	public int createContent(int publisherId, String contentType, String title,
			String description, String url) {

		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Content content = new Content();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			content.setPublisherId(publisherId);
			content.setType(contentType);
			content.setTitle(title);
			content.setDescription(description);
			content.setUrl(url);
			id = mapper.addContent(content);
		} finally {
			session.close();
		}
		return id;

	}

	public boolean addContentToTag(int tagId, int contentId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Paper[] papers;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			HashMap<String, Integer> inputMap = new HashMap<String, Integer>();
			inputMap.put("tagId", tagId);
			inputMap.put("contentId", contentId);
			papers = mapper.addContentToTag(inputMap);
		} finally {
			session.close();
		}
		return true;
	}

	public boolean removeContent(int contentId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Content content = new Content();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			mapper.removeContent(contentId);
		} finally {
			session.close();
		}
		return true;
	}

	public boolean removeContentFromTag(int tagId, int contentId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			HashMap<String, Integer> inputMap = new HashMap<String, Integer>();
			inputMap.put("tagId", tagId);
			inputMap.put("contentId", contentId);
			mapper.removeContentFromTag(inputMap);
		} finally {
			session.close();
		}
		return true;
	}

	public boolean updateContent(Content content) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			mapper.updateContent(content);
		} finally {
			session.close();
		}
		return true;
	}

	public Paper[] getPapers(int publisherId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Paper[] papers;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			papers = mapper.getPapers(publisherId);
		} finally {
			session.close();
		}
		return papers;
	}

	public Edition[] getEditions(int paperId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Edition[] editions = new Edition[0];
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			editions = mapper.getEditions(paperId);
		} finally {
			session.close();
		}
		return editions;
	}

	public Section[] getSections(int paperId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Section[] sections = new Section[0];
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			sections = mapper.getSections(paperId);
		} finally {
			session.close();
		}
		return sections;
	}

	/**
	 * 
	 * @param username
	 * @param publisher
	 * @param key
	 * @return validates whether the key is the correct key for this session for
	 *         this user
	 */
	public boolean isLoggedIn(String username, String key) {
		return true;
	}

	@Override
	public Paper getPaperDetails(int paperId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Paper paper = new Paper();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			paper = mapper.getPaper(paperId);
		} finally {
			session.close();
		}
		return paper;
	}

	@Override
	public int addSection(int paperId, String name) {

		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Section section = new Section();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			section.setPaperId(paperId);
			section.setName(name);
			id = mapper.addSection(section);
		} finally {
			session.close();
		}
		return id;
	}

	@Override
	public int addEdition(int paperId, String name) {

		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Edition edition = new Edition();
		int id = 0;
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			edition.setPaperId(paperId);
			edition.setName(name);
			id = mapper.addEdition(edition);
		} finally {
			session.close();
		}
		return id;
	}

	@Override
	public boolean removeSection(int paperId, String name) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Section section = new Section();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			section.setPaperId(paperId);
			section.setName(name);
			mapper.removeSection(section);
		} finally {
			session.close();
		}
		return true;
	}

	@Override
	public boolean removeEdition(int paperId, String name) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Edition edition = new Edition();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			edition.setPaperId(paperId);
			edition.setName(name);
			mapper.removeEdition(edition);
		} finally {
			session.close();
		}
		return true;
	}

	@Override
	public boolean changeDimensions(int paperId, float width, float height) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Paper paper = new Paper();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			paper.setId(paperId);
			paper.setHeight(height);
			paper.setWidth(width);
			mapper.changeDimensions(paper);
		} finally {
			session.close();
		}
		return true;
	}

	@Override
	public String viewPageJson(int arPageId) {
		Gson gson = new Gson();
		return gson.toJson(viewPage(arPageId, "na"));
	}

	@Override
	public boolean changeTagPlacement(int tagId, float x, float y, float width,
			float height) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		Tag tag = new Tag();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			tag.setId(tagId);
			tag.setHeight(height);
			tag.setWidth(width);
			tag.setStartx(x);
			tag.setStarty(y);
			mapper.changeTagPlacement(tag);
		} finally {
			session.close();
		}
		return true;
	}

	@Override
	public void incHits(int arPageId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			mapper.incHits(arPageId);
		} finally {
			session.close();
		}
	}

	@Override
	public int getHits(int arPageId) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			return mapper.getHits(arPageId);
		} finally {
			session.close();
		}
	}

	@Override
	public SectionStats[] getHitStats(int paperId, Date startDate, Date endDate) {
		DBHandler.getInstance();
		SqlSession session = DBHandler.sqlSessionFactory.openSession();
		try {
			DBMapper mapper = session.getMapper(DBMapper.class);
			return mapper.getHitStatsbySection(paperId, startDate, endDate);
		} finally {
			session.close();
		}

	}

}
